package org.xx.armory.spring5.mvc.converters;

import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalConverter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.xx.armory.commons.StringEnum;

import static org.apache.commons.lang3.StringUtils.trimToEmpty;

public class StringToStringEnumConverterFactory
        implements ConverterFactory<String, Enum<?>>, ConditionalConverter {
    @Override
    public <T extends Enum<?>> Converter<String, T> getConverter(Class<T> targetType) {
        return new EnumConverter<>(targetType);
    }

    @Override
    public boolean matches(
            TypeDescriptor sourceType,
            TypeDescriptor targetType
    ) {
        return targetType.isAssignableTo(TypeDescriptor.valueOf(StringEnum.class));
    }

    private static class EnumConverter<T extends Enum<?>> implements Converter<String, T> {
        private final Class<T> enumType;

        public EnumConverter(Class<T> enumType) {
            this.enumType = enumType;
        }

        @Override
        public T convert(String source) {
            source = trimToEmpty(source);
            if (source.isEmpty()) {
                return null;
            }

            final var ecs = enumType.getEnumConstants();
            for (final var ec : ecs) {
                final var sv = ((StringEnum) ec).stringValue();
                if (sv.equalsIgnoreCase(source)) {
                    return ec;
                }
            }
            throw new IllegalArgumentException("Cannot convert string \"" + source + "\" to " + enumType.getTypeName());
        }
    }
}
